import { canUse, isNull, isUndefined } from "mmb";
import {
  getBgsThirdpartyOpSafely,
  getMetadata,
  getOptionsOfLight,
  wrapperGrpcError,
} from "../grpc-client/grpcAdapter";
import * as thirdpartypb from "../grpc-client/others/thirdparty_pb";
import { getCache, setCache, makeEntityKey } from "../proxy/redisProxy";

const makeWechatCacheKey = makeEntityKey("wechat_proxy");

export interface WechatSession {
  openId: string;
  sessionKey: string;
  unionId: string;
}

export const getSessionByCode = async (
  code: string
): Promise<WechatSession> => {
  const cl = getBgsThirdpartyOpSafely();
  const req = new thirdpartypb.MinaCode2SessionReq();

  req.setJscode(code);

  return new Promise((resolve, reject) => {
    cl.minaCode2Session(req, getMetadata(), getOptionsOfLight(), (err, res) => {
      if (!isNull(err)) {
        reject(wrapperGrpcError(err.details));
        return;
      }
      resolve({
        openId: res.getOpenid(),
        sessionKey: res.getSessionkey(),
        unionId: res.getUnionid(),
      });
    });
  });
};

export interface DecryptMobileParams {
  sessionKey: string;
  encryptedData: string;
  iv: string;
}

export const decryptMobile = async ({
  sessionKey,
  encryptedData,
  iv,
}: DecryptMobileParams): Promise<string> => {
  const cl = getBgsThirdpartyOpSafely();
  const req = new thirdpartypb.MinaGetPhoneNumberReq();

  req.setSessionkey(sessionKey);
  req.setEncrypteddata(encryptedData);
  req.setIv(iv);

  return new Promise((resolve, reject) => {
    cl.minaGetPhoneNumber(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        resolve(res.getPhonenumber());
      }
    );
  });
};

export interface GetAccessTokenResult {
  accessToken: string;
  expiresIn: number;
}

export const getAccessToken = async (): Promise<GetAccessTokenResult> => {
  const cl = getBgsThirdpartyOpSafely();
  const req = new thirdpartypb.Empty();

  return new Promise((resolve, reject) => {
    cl.minaGetAccessToken(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        resolve({
          accessToken: res.getAccesstoken(),
          expiresIn: res.getExpiresin(),
        });
      }
    );
  });
};

export const getAccessTokenCachelly = async (): Promise<string> => {
  const k = makeWechatCacheKey("accessToken");
  const cv = await getCache(k);
  if (canUse(cv)) {
    console.log("accessToken hit cache ");
    return cv!;
  }

  const {accessToken, expiresIn} = await getAccessToken();
  await setCache(k, accessToken, expiresIn);
  return accessToken
};

export interface RGB {
  R: number;
  G: number;
  B: number;
}
export interface CreateQRParams {
  page: string;
  scene: string;
  width?: number;
  autoColor?: boolean;
  lineColor?: RGB;
  isHyaline?: boolean;
}

export const createQR = async ({
  page,
  scene,
  width,
  autoColor,
  lineColor,
  isHyaline,
}: CreateQRParams): Promise<string> => {
  const cl = getBgsThirdpartyOpSafely();
  const req = new thirdpartypb.MinaCreateQrCodeReq();

  req.setPage(page);
  const accessToken = await getAccessTokenCachelly()
  req.setAccesstoken(accessToken);
  req.setScene(scene);
  if (!isUndefined(width)) {
    req.setWidth(width);
  }
  if (!isUndefined(autoColor)) {
    req.setAutocolor(autoColor);
  }
  if (!isUndefined(lineColor)) {
    const pb = new thirdpartypb.MinaCreateQrCodeReq.RGB();
    pb.setR(lineColor.R);
    pb.setG(lineColor.G);
    pb.setB(lineColor.B);
    req.setLinecolor(pb);
  }
  if (!isUndefined(isHyaline)) {
    req.setIshyaline(isHyaline);
  }

  return new Promise((resolve, reject) => {
    cl.minaCreateQrCode(req, getMetadata(), getOptionsOfLight(), (err, res) => {
      if (!isNull(err)) {
        reject(wrapperGrpcError(err.details));
        return;
      }
      resolve(res.getUri());
    });
  });
};
